package wiki.xsx.core.handler;

import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 哈希类型助手
 * @author xsx
 * @date 2019/4/9
 * @since 1.8
 */
public class HashTypeHandler {
    /**
     * 对象模板
     */
    private HashOperations<String, String, Object> hashOperations;
    /**
     * 字符串模板
     */
    private HashOperations<String, String, String> stringHashOperations;
    /**
     * 单例对象
     */
    private static final HashTypeHandler HANDLER = new HashTypeHandler();

    private HashTypeHandler(){}

    public static HashTypeHandler getInstance(RedisTemplate redisTemplate, StringRedisTemplate stringRedisTemplate){
        HANDLER.hashOperations = redisTemplate.opsForHash();
        HANDLER.stringHashOperations = stringRedisTemplate.opsForHash();
        return HANDLER;
    }

    /**
     * 存入对象
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param value 对象
     */
    public void putAsObj(String key, String hashKey, Object value){
        this.hashOperations.put(key, hashKey, value);
    }

    /**
     * 存入字符串
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param value 字符串
     */
    public void put(String key, String hashKey, String value){
        this.stringHashOperations.put(key, hashKey, value);
    }

    /**
     * 存入对象如果不存在
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param value 对象
     * @return 返回布尔值,成功true,失败false
     */
    public boolean putIfAbsentAsObj(String key, String hashKey, Object value){
        return this.hashOperations.putIfAbsent(key, hashKey, value);
    }

    /**
     * 存入字符串如果不存在
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param value 字符串
     * @return 返回布尔值,成功true,失败false
     */
    public boolean putIfAbsent(String key, String hashKey, String value){
        return this.stringHashOperations.putIfAbsent(key, hashKey, value);
    }

    /**
     * 存入对象集合
     * @since redis 2.0.0
     * @param key 键
     * @param map 对象集合
     */
    public void putAllAsObj(String key, Map<String, Object> map){
        this.hashOperations.putAll(key, map);
    }

    /**
     * 存入字符串集合
     * @since redis 2.0.0
     * @param key 键
     * @param map 字符串集合
     */
    public void putAll(String key, Map<String, String> map){
        this.stringHashOperations.putAll(key, map);
    }

    /**
     * 获取对象
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param <T> 返回类型
     * @return 返回对象
     */
    public <T> T getAsObj(String key, String hashKey){
        return (T) this.hashOperations.get(key, hashKey);
    }

    /**
     * 获取字符串
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @return 返回字符串
     */
    public String get(String key, String hashKey){
        return this.stringHashOperations.get(key, hashKey);
    }

    /**
     * 批量获取对象
     * @since redis 2.0.0
     * @param key 键
     * @param hashKeys hash键
     * @return 返回对象列表
     */
    public List mgetAsObj(String key, String ...hashKeys){
        return this.hashOperations.multiGet(key, Arrays.asList(hashKeys));
    }

    /**
     * 批量获取字符串
     * @since redis 2.0.0
     * @param key 键
     * @param hashKeys hash键
     * @return 返回字符串列表
     */
    public List<String> mget(String key, String ...hashKeys){
        return this.stringHashOperations.multiGet(key, Arrays.asList(hashKeys));
    }

    /**
     * 移除对象
     * @since redis 2.0.0
     * @param key 键
     * @param hashKeys hash键
     * @return 返回移除数量
     */
    public Long removeAsObj(String key, String ...hashKeys){
        return this.hashOperations.delete(key, Arrays.asList(hashKeys).toArray());
    }

    /**
     * 移除字符串
     * @since redis 2.0.0
     * @param key 键
     * @param hashKeys hash键
     * @return 返回移除数量
     */
    public Long remove(String key, String ...hashKeys){
        return this.stringHashOperations.delete(key, Arrays.asList(hashKeys).toArray());
    }

    /**
     * 获取对象集合
     * @since redis 2.0.0
     * @param key 键
     * @return 返回对象字典
     */
    public Map<String, Object> entriesAsObj(String key){
        return this.hashOperations.entries(key);
    }

    /**
     * 获取字符串集合
     * @since redis 2.0.0
     * @param key 键
     * @return 返回字符串字典
     */
    public Map<String, String> entries(String key){
        return this.stringHashOperations.entries(key);
    }

    /**
     * 获取对象hash键集合
     * @since redis 2.0.0
     * @param key 键
     * @return 返回对象字典键集合
     */
    public Set keysAsObj(String key){
        return this.hashOperations.keys(key);
    }

    /**
     * 获取字符串hash键集合
     * @since redis 2.0.0
     * @param key 键
     * @return 返回字符串字典键集合
     */
    public Set<String> keys(String key){
        return this.stringHashOperations.keys(key);
    }

    /**
     * 获取对象集合
     * @since redis 2.0.0
     * @param key 键
     * @return 返回对象列表
     */
    public List valuesAsObj(String key){
        return this.hashOperations.values(key);
    }

    /**
     * 获取字符串集合
     * @since redis 2.0.0
     * @param key 键
     * @return 返回字符串列表
     */
    public List<String> values(String key){
        return this.stringHashOperations.values(key);
    }

    /**
     * 获取字符串长度
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @return 返回字符串长度
     */
    public Long lengthOfValue(String key, String hashKey){
        return this.stringHashOperations.lengthOfValue(key, hashKey);
    }

    /**
     * 获取对象数量
     * @since redis 3.2.0
     * @param key 键
     * @return 返回对象数量
     */
    public Long sizeAsObj(String key){
        return this.hashOperations.size(key);
    }

    /**
     * 获取字符串数量
     * @since redis 3.2.0
     * @param key 键
     * @return 返回字符串数量
     */
    public Long size(String key){
        return this.stringHashOperations.size(key);
    }

    /**
     * 是否包含对象的key
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @return 返回布尔值,存在true,不存在false
     */
    public boolean hasKeyAsObj(String key, String hashKey){
        return this.hashOperations.hasKey(key, hashKey);
    }

    /**
     * 是否包含字符串的key
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @return 返回布尔值,存在true,不存在false
     */
    public boolean hasKey(String key, String hashKey){
        return this.stringHashOperations.hasKey(key, hashKey);
    }

    /**
     * 自增
     * @since redis 2.6.0
     * @param key 键
     * @param hashKey hash键
     * @param data 步长
     * @return 返回自增后的值
     */
    public Double increment(String key, String hashKey, Double data){
        return this.stringHashOperations.increment(key, hashKey, data);
    }

    /**
     * 自增
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param data 步长
     * @return 返回自增后的值
     */
    public Long increment(String key, String hashKey, Long data){
        return this.stringHashOperations.increment(key, hashKey, data);
    }

    /**
     * 自增
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @return 返回自增后的值
     */
    public Long increment(String key, String hashKey){
        return this.stringHashOperations.increment(key, hashKey, 1L);
    }

    /**
     * 递减
     * @since redis 2.0.0
     * @param key 键
     * @param hashKey hash键
     * @param data 步长
     * @return 返回递减后的值
     */
    public Long decrement(String key, String hashKey, Long data){
        return this.stringHashOperations.increment(key, hashKey, -data);
    }

    /**
     * 递减
     * @since redis 2.6.0
     * @param key 键
     * @param hashKey hash键
     * @return 返回递减后的值
     */
    public Long decrement(String key, String hashKey){
        return this.stringHashOperations.increment(key, hashKey, -1L);
    }
}
